﻿using System;
using System.ServiceModel;
using System.Xml;
using System.Collections.Generic;
using System.Data;
using System.Text;
using System.IO;
using SdmxMl.Common;
using SdmxMl.Structure;
using SdmxMl.Registry;
using SdmxMl.GenericMetadata;
using SdmxMl.Manager;
using System.Xml.Serialization;

namespace SdmxMl.Helper
{
      [XmlRoot("Ref")]
    public class Referrer
    {
          private string _urn;

        public string Type { get; set; }

        public string Urn 
        {
            get { return _urn; }
            set
            {
                _urn = value;
                UrnParser up = new UrnParser(_urn);
                if (up.IsSupported)
                {
                    Agency = up.AgencyId;
                    Id = up.ArtefactId;
                    Version = up.Version;
                }
            }
        }
        
          [XmlIgnore]
        public string Agency { get; private set; }
          [XmlIgnore]
          public string Id { get; private set; }
          [XmlIgnore]
          public string Version { get; private set; }

        public Referrer()
        {
            Type = _urn = string.Empty;
        }

        public Referrer(string type, string urn)
        {
            this.Type = type;
            Urn = urn;
        }
    }


    public class ReferenceMaker
    {
        public const string FILE_ENDER = "Referenced.xml";

        List<string> subDirs;
        private string root;
        private SmManager smMSD;

        private string destinationDir;
        private Dictionary<string, string> dicoUriConcept;

        SerializableDictionary<string, List<Referrer>> dicoRefCodelist;
        SerializableDictionary<string, List<Referrer>> dicoRefConceptScheme;


        public ReferenceMaker(string rootPath)
        {
            root = rootPath;
            destinationDir = @"P:\Projekte\Public\SMS\ReferBase\";
          //  destinationDir = @"c:\doc\";

            dicoRefCodelist = new SerializableDictionary<string, List<Referrer>>();
            dicoRefConceptScheme = new SerializableDictionary<string, List<Referrer>>();

            subDirs = new List<string>();
            subDirs.Add("Concepts");
            subDirs.Add("KeyFamilies");
            subDirs.Add("HierarchicalCodeLists");
            subDirs.Add("MetadataStructureDefinitions");
            subDirs.Add("StructureSets");
            subDirs.Add("MetadataSet");
        }

        public void Scan()
        {
            SmManager sm = new SmManager();
            smMSD = new SmManager();
            foreach (string sub in subDirs)
            {
                string dir = root + sub;
                string[] list = Directory.GetFiles(dir, "*.xml");
                foreach (string file in list)
                {
                    sm.LoadSdmxDocument(file, false, null);
                    foreach (ArtefactManager mgr in sm.ArtefactManagerDico.Values)
                    {
                        if( mgr != null && mgr.Count > 0)
                        {
                            Artefact a = mgr.ArtefactList[0];
                            ArtefactRefTypedList arList = a.ArtefactRefList;
                            if (a.ArType == SdmxArtefactType.MetadataStructureDefinitions)
                            {
                                smMSD.PutArtefact(SdmxArtefactType.MetadataStructureDefinitions, a);
                            }
                            else if (a.ArType == SdmxArtefactType.MetadataSet)
                            {
                                dicoUriConcept = new Dictionary<string, string>();
                                AddMetasetRef(a, arList);
                            }

                            foreach(ArtefactRefTyped art in arList)
                            {
                                if (art.Type == SdmxArtefactType.CodeLists || art.Type == SdmxArtefactType.HierarchicalCodelists)
                                {
                                    if (dicoRefCodelist.ContainsKey(art.FullIdent) == false)
                                    {
                                        dicoRefCodelist.Add(art.FullIdent, new List<Referrer>());
                                    }
                                    string urn = UrnManager.FullIdToUrn(a.ArType, a.FullIdent);
                                    if (dicoRefCodelist[art.FullIdent].Find(x => x.Urn == urn) == null)
                                    {
                                        dicoRefCodelist[art.FullIdent].Add(new Referrer(a.ArType.ToString(), urn));
                                    }
                                }
                                else if (art.Type == SdmxArtefactType.Concepts)
                                {
                                    if (dicoRefConceptScheme.ContainsKey(art.FullIdent) == false)
                                    {
                                        dicoRefConceptScheme.Add(art.FullIdent, new List<Referrer>());
                                    }
                                    string urn = UrnManager.FullIdToUrn(a.ArType, a.FullIdent);
                                    if (dicoRefConceptScheme[art.FullIdent].Find(x => x.Urn == urn) == null)
                                    {
                                        dicoRefConceptScheme[art.FullIdent].Add(new Referrer(a.ArType.ToString(), urn));
                                    }
                                }

                            }
                            break;
                        }
                    }

                }
            }

            // Now serialize
            XmlSerializer serializer = new XmlSerializer(typeof(SerializableDictionary<string, List<Referrer>>));
            string destPath = destinationDir + SdmxArtefactType.CodeLists.ToString() + FILE_ENDER;
            TextWriter textWriter = new StreamWriter(destPath);
            serializer.Serialize(textWriter, dicoRefCodelist);
            textWriter.Close();

            serializer = new XmlSerializer(typeof(SerializableDictionary<string, List<Referrer>>));
            destPath = destinationDir + SdmxArtefactType.Concepts.ToString() + FILE_ENDER;
            textWriter = new StreamWriter(destPath);
            serializer.Serialize(textWriter, dicoRefConceptScheme);
            textWriter.Close();

        }

        private void AddMetasetRef(Artefact a, ArtefactRefTypedList arList)
        {
            MetadataSetType metaSet = a as MetadataSetType;
            if (metaSet != null)
            {
                MetadataStructureDefinitionType msd =
                    smMSD.GetArtefact(SdmxArtefactType.MetadataStructureDefinitions, metaSet.MetadataStructureRef) as MetadataStructureDefinitionType;
                ReportStructureType report = msd.ReportStructureList.LocateItem(metaSet.ReportRef);

                // Get Reportedattribute of type URI
                IterateHierarchyMetaAttrib(msd, report, report.MetadataAttributeList);

                // Now scan whole datas (if ans URI)
                if (dicoUriConcept.Count > 0)
                {
                    foreach (string conceptId in dicoUriConcept.Keys)
                    {
                        // For each meta row
                        foreach (AttributeValueSetType at in metaSet.AttributeValueSetList)
                        {
                            // Get URI value
                            ReportedAttributeType rptAtt = at.ReportedAttributeList.GetReportedAttributeOfConcept(conceptId);
                            string urn = rptAtt != null ? rptAtt.Value.GetFirst() : string.Empty;
                            ArtefactRefTyped art = null;
                            if (urn.StartsWith(UrnManager.UrnBase))
                            {
                                UrnParser p = new UrnParser(urn);
                                if (p.IsSupported)
                                {
                                    // If not yet loaded or not already recorded
                                    // add unknown references of artefact in dico list
                                    art = new ArtefactRefTyped(p.ArType, p.ArtefactId, p.AgencyId, p.Version);
                                    if (arList.Contains(art.Type, art.FullIdent) == false)
                                        arList.Add(art);

                                }


                            }
                        }

                    }

                }


            }

        }

        private void IterateHierarchyMetaAttrib(MetadataStructureDefinitionType msd, ReportStructureType rpt, MetadataAttributeTypeList metaList)
        {
            foreach (MetadataAttributeType meta in metaList)
            {
                // record case using URI in metadataset, for next domain search
                if (meta.TextFormat.TextType == TextTypeType.URI &&
                    meta.ConceptSchemeInfo.IsFilled && meta.ConceptInfo.Id.Length > 0)
                {
                    if (this.dicoUriConcept.ContainsKey(meta.ConceptInfo.Id) == false)
                        this.dicoUriConcept.Add(meta.ConceptInfo.Id, meta.ConceptSchemeInfo.FullIdent);
                }

                IterateHierarchyMetaAttrib(msd, rpt, meta.MetadataAttributeList);
            }
        }

    }
}
